﻿using Microsoft.AspNetCore.Identity;

namespace Admin.NET.Core;

/// <summary>
/// 实现切换数据库后操作.
/// </summary>
public class DataBaseManager : IScoped
{
    /// <summary>
    /// 初始化客户端.
    /// </summary>
    private static SqlSugarScope? _sqlSugarClient;

    private readonly UserManager _userManager;

    public DataBaseManager(ISqlSugarClient context, UserManager userManager)
    {
        _sqlSugarClient = (SqlSugarScope)context;
        _userManager = userManager;
    }

    /// <summary>
    /// 数据库切换.
    /// </summary>
    /// <param name="link">数据连接.</param>
    /// <returns>切库后的SqlSugarClient.</returns>
    public SqlSugarScope ChangeDataBase(SysDbLink link)
    {
        if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId.ToString() != link.Id.ToString())
        {
            if (_sqlSugarClient.AsTenant().IsAnyConnection(link.Id))
            {
                _sqlSugarClient.ChangeDatabase(link.Id);
            }
            else
            {
                _sqlSugarClient.AddConnection(new ConnectionConfig()
                {
                    ConfigId = link.Id,
                    DbType = ToDbType(link.DBType),
                    ConnectionString = ToConnectionString(link),
                    InitKeyType = InitKeyType.Attribute,
                    IsAutoCloseConnection = true
                });

                _sqlSugarClient.Ado.CommandTimeOut = 30;

                //_sqlSugarClient.Aop.OnLogExecuting = (sql, pars) =>
                //{
                //    if (sql.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase))
                //        Console.ForegroundColor = ConsoleColor.Green;
                //    if (sql.StartsWith("UPDATE", StringComparison.OrdinalIgnoreCase) || sql.StartsWith("INSERT", StringComparison.OrdinalIgnoreCase))
                //        Console.ForegroundColor = ConsoleColor.White;
                //    if (sql.StartsWith("DELETE", StringComparison.OrdinalIgnoreCase))
                //        Console.ForegroundColor = ConsoleColor.Blue;

                //    // 在控制台输出sql语句
                //    Console.WriteLine("【" + DateTime.Now + "——执行SQL】\r\n" + UtilMethods.GetSqlString(_sqlSugarClient.CurrentConnectionConfig.DbType, sql, pars) + "\r\n");
                //};

                //_sqlSugarClient.Aop.OnError = (ex) =>
                //{
                //    Console.ForegroundColor = ConsoleColor.Red;
                //    var pars = _sqlSugarClient.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
                //    Console.WriteLine("【" + DateTime.Now + "——错误SQL】\r\n" + UtilMethods.GetSqlString(_sqlSugarClient.CurrentConnectionConfig.DbType, ex.Sql, (SugarParameter[])ex.Parametres) + "\r\n");
                //};

                if (_sqlSugarClient.CurrentConnectionConfig.DbType == SqlSugar.DbType.Oracle)
                {
                    _sqlSugarClient.Aop.OnExecutingChangeSql = (sql, pars) =>
                    {
                        if (pars != null)
                        {
                            foreach (var item in pars)
                            {
                                // 如果是DbTppe=string设置成OracleDbType.Nvarchar2
                                item.IsNvarchar2 = true;
                            }
                        }
                        return new KeyValuePair<string, SugarParameter[]>(sql, pars);
                    };
                }
                _sqlSugarClient.ChangeDatabase(link.Id);
            }
        }
        return _sqlSugarClient;
    }

    /// <summary>
    /// 转换数据库类型.
    /// </summary>
    /// <param name="dbType">数据库类型.</param>
    /// <returns></returns>
    public SqlSugar.DbType ToDbType(string dbType)
    {
        switch (dbType.ToLower())
        {
            case "sqlserver":
                return SqlSugar.DbType.SqlServer;

            case "mysql":
                return SqlSugar.DbType.MySql;

            case "oracle":
                return SqlSugar.DbType.Oracle;

            case "dm8":
            case "dm":
                return SqlSugar.DbType.Dm;

            case "kdbndp":
            case "kingbasees":
                return SqlSugar.DbType.Kdbndp;

            case "postgresql":
                return SqlSugar.DbType.PostgreSQL;

            default:
                throw Oops.Oh(ErrorCodeEnum.D1506);
        }
    }

    /// <summary>
    /// 转换连接字符串.
    /// </summary>
    /// <param name="dbLinkEntity">数据连接.</param>
    /// <returns></returns>
    public string ToConnectionString(SysDbLink dbLinkEntity)
    {
        switch (dbLinkEntity.DBType.ToLower())
        {
            case "sqlserver":
                return string.Format("Data Source={0},{4};Initial Catalog={1};User ID={2};Password={3};MultipleActiveResultSets=true", dbLinkEntity.Host, dbLinkEntity.ServiceName, dbLinkEntity.UserName, dbLinkEntity.Password, dbLinkEntity.Port);
            case "oracle":
                var oracleParam = dbLinkEntity.OracleParam.ToObject<OracleParamModel>();
                if (oracleParam.oracleExtend)
                {
                    return string.Format("Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST={0})(PORT={1}))(CONNECT_DATA=(SERVER = DEDICATED)(SERVICE_NAME={2})));User Id={3};Password={4}", dbLinkEntity.Host, dbLinkEntity.Port.ToString(), oracleParam.oracleService, dbLinkEntity.UserName, dbLinkEntity.Password);
                }
                else
                {
                    return string.Format("Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST={0})(PORT={1}))(CONNECT_DATA=(SERVER = DEDICATED)(SERVICE_NAME=ORCL)));User Id={2};Password={3}", dbLinkEntity.Host, dbLinkEntity.Port.ToString(), dbLinkEntity.UserName, dbLinkEntity.Password);
                }

            case "mysql":
                return string.Format("server={0};port={1};database={2};user={3};password={4};AllowLoadLocalInfile=true", dbLinkEntity.Host, dbLinkEntity.Port.ToString(), dbLinkEntity.ServiceName, dbLinkEntity.UserName, dbLinkEntity.Password);
            case "dm8":
            case "dm":
                return string.Format("server={0};port={1};database={2};User Id={3};PWD={4}", dbLinkEntity.Host, dbLinkEntity.Port.ToString(), dbLinkEntity.ServiceName, dbLinkEntity.UserName, dbLinkEntity.Password);
            case "kdbndp":
            case "kingbasees":
                return string.Format("server={0};port={1};database={2};UID={3};PWD={4}", dbLinkEntity.Host, dbLinkEntity.Port.ToString(), dbLinkEntity.ServiceName, dbLinkEntity.UserName, dbLinkEntity.Password);
            case "postgresql":
                return string.Format("server={0};port={1};Database={2};User Id={3};Password={4};searchpath={5};", dbLinkEntity.Host, dbLinkEntity.Port.ToString(), dbLinkEntity.ServiceName, dbLinkEntity.UserName, dbLinkEntity.Password, dbLinkEntity.DBSchema);
            default:
                throw Oops.Oh(ErrorCodeEnum.D1506);
        }
    }

    /// <summary>
    /// 切换默认库.
    /// </summary>
    /// <param name="linkEntity"></param>
    private void ChangeDefaultDatabase(SysDbLink linkEntity)
    {
        if (SqlSugarConst.MainConfigId != _userManager.TenantId.ToString())
        {
            if (_userManager.TenantId.IsNullOrEmpty())
            {
                _sqlSugarClient.ChangeDatabase(_userManager.TenantId);
            }
            else
            {
                _sqlSugarClient.ChangeDatabase(linkEntity.Id);
            }
        }
        else
        {
            _sqlSugarClient.ChangeDatabase(SqlSugarConst.MainConfigId);
        }
    }

    /// <summary>
    /// 测试数据库连接.
    /// </summary>
    /// <param name="link">数据连接.</param>
    /// <returns></returns>
    public bool IsConnection(SysDbLink link)
    {
        _sqlSugarClient = ChangeDataBase(link);
        var flag = _sqlSugarClient.Ado.IsValidConnection();
        ChangeDefaultDatabase(link);
        return flag;
    }
}